package com.weir.r2dbc;

import java.util.ArrayList;
import java.util.List;

import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.info.BuildProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
//import io.swagger.v3.oas.annotations.OpenAPIDefinition;
//import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
//import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
//import io.swagger.v3.oas.annotations.responses.ApiResponse;
//import io.swagger.v3.oas.annotations.responses.ApiResponses;
//import io.swagger.v3.oas.annotations.security.SecurityScheme;
//import io.swagger.v3.oas.annotations.info.Info;
//import io.swagger.v3.oas.models.Components;
//import io.swagger.v3.oas.models.OpenAPI;
//import io.swagger.v3.oas.models.headers.Header;
//import io.swagger.v3.oas.models.info.Info;
//import io.swagger.v3.oas.models.info.License;
//import io.swagger.v3.oas.models.media.StringSchema;
//import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;


@SpringBootApplication
public class R2dbcDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(R2dbcDemoApplication.class, args);
	}

	
}


@Data
@AllArgsConstructor
@NoArgsConstructor
class Orders {

	@Id
	private Long id;

	private String fn;

}
@Repository
interface OrdersRepository extends ReactiveSortingRepository<Orders, Long> {
	@Query("SELECT * FROM orders LIMIT :limit OFFSET :offset")
	Flux<Orders> findById(int offset, int limit);
	
	Flux<Orders> findByFnLike(String fn,Pageable pageable);

}
//interface OrdersRepository extends ReactiveCrudRepository<Orders, Long> {
//	@Query("SELECT * FROM orders LIMIT :limit OFFSET :offset")
//	Flux<Orders> findById(int offset, int limit);
//
//}

@RestController
@RequestMapping("/order")
class OrdersController {
	@Autowired
	OrdersRepository ordersRepository;

//	@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "order_all") })
//	@GetMapping("/order_all")
//	public Flux<Orders> findAll() {
//		return ordersRepository.findAll();
//	}

	@GetMapping("/init")
	public Flux<Orders> init() {
		List<Orders> list = new ArrayList<>();
		for (int i = 0; i < 20; i++) {
			Orders orders = new Orders();
//			orders.setId(10l + i);
			orders.setFn("weir" + i);
			list.add(orders);
		}
		return ordersRepository.saveAll(list);
	}

//	@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "page") })
	@GetMapping("/page")
	public Flux<Orders> page() {
		return ordersRepository.findById(0, 10);
	}
	
//	@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "page") })
	@GetMapping("/page-1")
	public Flux<Orders> page(@RequestParam(value = "page", required = false, defaultValue = "0") Integer page,
			@RequestParam(value = "pageSize", required = false, defaultValue = "2") Integer pageSize, 
			@RequestParam(value = "fn", required = false) String fn) {
		if (!StringUtils.isEmpty(fn)) {
			fn = "%" + fn + "%";
		}
		Sort sort = Sort.by(Direction.DESC, "fn");
		Pageable pageable = PageRequest.of(page, pageSize, sort);
		
		Flux<Orders> flux = ordersRepository.findByFnLike( fn,pageable);
//		Flux<Orders> flux = ordersRepository.findByFnLike( fn,PageRequest.of(page, pageSize));
		return flux;
	}
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {

	@Id
	private Long id;
	private String firstname;
	private String lastname;

}
interface PersonRepository extends ReactiveCrudRepository<Person, Long> {
	Flux<Person> findByFirstname(String firstname);

	Flux<Person> findByFirstname(Publisher<String> firstname);

	Flux<Person> findByFirstnameOrderByLastname(String firstname, Pageable pageable);

	Mono<Person> findByFirstnameAndLastname(String firstname, String lastname);

	Mono<Person> findFirstByLastname(String lastname);

	@Query("SELECT * FROM person WHERE lastname = :lastname")
	Flux<Person> findByLastname(String lastname);

//	@Query("SELECT firstname, lastname FROM person WHERE lastname = $1")
//	Mono<Person> findFirstByLastname(String lastname);
}

@RestController
@RequestMapping("/person")
class PersonController{

	@Autowired
	PersonRepository personRepository;

//	@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "/findByFirstname/{firstname}") })
	@GetMapping("/findByFirstname/{firstname}")
	public void findByFirstname(@PathVariable String firstname) {
		personRepository.findByFirstname(firstname);
	}
}
